#pragma once
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include "Protocol.hpp"
#include "../Connection.hpp"
#include "Request&&Response.hpp"
#include "../RoomPlayers.hpp"
#include "../Collision.hpp"

// 玩家准备时的请求以及响应格式
// 请求报文中会表明这是一个玩家准备的报文
// Request: CreateRoom -> $len${ "server_type" : "QuitRoom"}
// 响应会处理请求报文，本地直接退出即可

static Point Rotate(Point center, Point d, double a)
{
    a = -a; // 注意，屏幕坐标 y 轴向下，故旋转弧度取反
    Point r;
    r._x = (d._x - center._x) * cos(a) - (d._y - center._y) * sin(a) + center._x;
    r._y = (d._x - center._x) * sin(a) + (d._y - center._y) * cos(a) + center._y;
    return r;
}

extern std::vector<std::vector<int>> _battlefield_rgb;

extern std::unordered_map<std::string, Room *> rooms;
extern std::unordered_map<int, std::string> fd_to_room_number;

class RequestSwordMove : public Request
{
public:
    RequestSwordMove() {}

    virtual bool Serialize(std::string *msg)
    {
        // Json::Value root;
        // root["server_type"] = PlayerMove;
        // root["player_id"] = player_id;
        // root["player_to_right"] = _player_to_right;
        // root["player_to_left"] = _player_to_left;
        // root["player_to_up"] = _player_to_up;
        // root["player_to_down"] = _player_to_down;
        // //root["room_number"] = _room_number;
        // Json::FastWriter writer;
        // *msg = writer.write(root);

        return true;
    }
    virtual bool Deserialize(const Json::Value &root)
    {
        _player_id = root["player_id"].asInt();
        int64_t peer_time = std::stoull(root["player_id"].asString());
        _radian = root["radian"].asDouble();
        _rotation_direction = root["rotation_direction"].asInt();
        // _x = root["player_x"].asDouble();
        // _y = root["player_y"].asDouble();
        return true;
    }

    void SetRadian(double radian)
    {
        _radian = radian;
    }

    ~RequestSwordMove() {}

public:
    // double _x = 0, _y = 0;
    int _player_id = 0;
    double _radian = 0;
    int _rotation_direction = 0;
};

void OppositeDirection(int &rotation_direction)
{
    if (rotation_direction == clockwise)
        rotation_direction = anticlockwise;
    else
        rotation_direction = clockwise;
}

// std::vector<Point> GetCorner(const RequestSwordMove *req)
std::vector<Point> GetCorner(Point p, double _radian)
{
    std::vector<Point> ret;
    // -_radian
    // -(_radian - initial_radian)
    ret.push_back(Rotate(p, {p._x - g_sword_width / 2, p._y - g_radius - 10 - g_sword_height}, -(_radian))); // 左上角
    ret.push_back(Rotate(p, {p._x - g_sword_width / 2, p._y - g_radius - 10}, -(_radian)));                  // 左下角
    ret.push_back(Rotate(p, {p._x + g_sword_width / 2, p._y - g_radius - 10}, -(_radian)));                  // 右下角
    ret.push_back(Rotate(p, {p._x + g_sword_width / 2, p._y - g_radius - 10 - g_sword_height}, -(_radian))); // 右上角

    return ret;
}

std::vector<std::pair<int, int>> GetSurroundingMatrix(Player &player)
{
    // Point p = _player_ptr->GetCenterPoint();
    std::vector<Point> cornor = GetCorner({player._x, player._y}, player._sword._radian);
    Point top_left_corner = cornor[0];
    Point bottom_left_corner = cornor[1];
    Point bottom_right_corner = cornor[2];
    Point top_right_corner = cornor[3];

    std::vector<std::pair<int, int>> ret;
    double min_x = std::min<double>({top_left_corner._x, top_right_corner._x, bottom_left_corner._x, bottom_right_corner._x});
    double min_y = std::min<double>({top_left_corner._y, top_right_corner._y, bottom_left_corner._y, bottom_right_corner._y});
    double max_x = std::max<double>({top_left_corner._x, top_right_corner._x, bottom_left_corner._x, bottom_right_corner._x});
    double max_y = std::max<double>({top_left_corner._y, top_right_corner._y, bottom_left_corner._y, bottom_right_corner._y});

    int min_row = min_y / block_size;
    int max_row = std::min((int)ceil(max_y / block_size), window_height / block_size);
    int min_col = min_x / block_size;
    int max_col = std::min((int)ceil(max_x / block_size), window_width / block_size);
    ret.push_back({min_row, min_col});
    ret.push_back({max_row, min_col});
    ret.push_back({max_row, max_col});
    ret.push_back({min_row, max_col});

    return ret;
}

std::vector<std::pair<int, int>> CheckBlockCollision(Player &player)
{
    std::vector<std::pair<int, int>> vertex = GetSurroundingMatrix(player);

    std::vector<std::pair<int, int>> ret;
    for (int i = vertex[0].second; i < vertex[2].second; i++)
    {
        for (int j = vertex[0].first; j < vertex[1].first; j++)
        {
            double x = i * 20, y = j * 20;
            std::vector<Point> corner1 = {
                {x, y},
                {x, y + block_size},
                {x + block_size, y + block_size},
                {x + block_size, y}};

            std::vector<Point> corner2 = GetCorner({player._x, player._y}, player._sword._radian);

            if (Collision::CheckCollision(corner1, corner2))
            {
                if (_battlefield_rgb[j][i] != player._color)
                {
                    _battlefield_rgb[j][i] = player._color;
                    ret.push_back({j, i});
                }
            }
        }
    }

    return ret;
}

bool CheckSwordCollision(Player &player1, Player &player2)
{
    std::vector<Point> corner1 = GetCorner({player1._x, player1._y}, player1._sword._radian);
    std::vector<Point> corner2 = GetCorner({player2._x, player2._y}, player2._sword._radian);
    if (Collision::CheckCollision(corner1, corner2))
    {
        while (Collision::CheckCollision(corner1, corner2))
        {
            player1._sword._radian -= 0.3 * player1._sword.rotation_direction;
            corner1 = GetCorner({player1._x, player1._y}, player1._sword._radian);
            corner2 = GetCorner({player2._x, player2._y}, player2._sword._radian);
        }
        OppositeDirection(player1._sword.rotation_direction);
        OppositeDirection(player2._sword.rotation_direction);
        return true;
    }
    return false;
}

bool CheckPlayerCollision(Player &player1, Player &player2)
{
    Point p = {player2._x, player2._y};
    std::vector<Point> corner1 = GetCorner({player1._x, player1._y}, player1._sword._radian);
    std::vector<Point> corner2 = {p, {p._x + 1, p._y + 1}};
    if (Collision::CheckCollision(corner1, corner2))
    {
        // 同步本地玩家状态
        player2._color = player1._color;
        return true;
    }
    return false;
}

bool CheckEdgeCollision(Player &player)
{

    std::vector<Point> Corner = GetCorner({player._x, player._y}, player._sword._radian);
    Point top_left_corner = Corner[0];
    if (top_left_corner._x <= 0 || top_left_corner._x >= window_width || top_left_corner._y <= 0 || top_left_corner._y >= window_height)
        return true;

    Point bottom_left_corner = Corner[1];
    if (bottom_left_corner._x <= 0 || bottom_left_corner._x >= window_width || bottom_left_corner._y <= 0 || bottom_left_corner._y >= window_height)
        return true;

    Point bottom_right_corner = Corner[2];
    if (bottom_right_corner._x <= 0 || bottom_right_corner._x >= window_width || bottom_right_corner._y <= 0 || bottom_right_corner._y >= window_height)
        return true;

    Point top_right_corner = Corner[3];
    if (top_right_corner._x <= 0 || top_right_corner._x >= window_width || top_right_corner._y <= 0 || top_right_corner._y >= window_height)
        return true;

    return false;
}

class ResponseSwordMove : public Response
{
public:
    ResponseSwordMove() {}

    virtual bool Serialize(std::string *msg)
    {
        return true;
    }

    // 收到客户端发来的退出的请求时，服务器端需要向处在房间的其他人发送退出房间信号
    bool ServerHandler(const RequestSwordMove *req, Connection *conn)
    {
        std::vector<Player> &players = rooms[fd_to_room_number[conn->GetFd()]]->GetPlayers();
        std::string cur_member = rooms[fd_to_room_number[conn->GetFd()]]->GetPlayersNumber();


        // players[req->_player_id]._sword._radian = req->_radian;
        // players[req->_player_id]._sword.rotation_direction = req->_rotation_direction;

        // 检测宝剑是否与战场不同方块发生碰撞
        {
            // std::cout << "_battlefield_rgb" << std::endl;
            // std::cout << req->_player_id << " " << players[req->_player_id]._color << std::endl;
            // for(int i = 0; i < _battlefield_rgb.size(); i++)
            // {
            //     for(int j = 0; j < _battlefield_rgb[0].size(); j++)
            //     {
            //         std::cout << _battlefield_rgb[i][j];
            //     }
            //     std::cout << std::endl;
            // }
            // std::cout << std::endl;

            std::vector<std::pair<int, int>> ret = CheckBlockCollision(players[req->_player_id]);
            if (ret.size() > 0)
            {
                std::string msg;
                Json::Value root;
                root["server_type"] = BlockCollision;
                root["color"] = players[req->_player_id]._color;
                // std::cout << "@@@@@@@@@@" << std::endl;
                for (int i = 0; i < ret.size(); i++)
                {
                    std::string count = std::to_string(i);
                    root[count] = std::to_string(ret[i].first) + " " + std::to_string(ret[i].second);
                }
                // std::cout << "@@@@@@@@@@" << std::endl;

                Json::FastWriter writer;
                msg = writer.write(root);
                // std::cout << "BlockCollision msg: " << msg;
                // std::cout << "Player coor : " << players[req->_player_id]._x << " " << players[req->_player_id]._y << msg;
                Package(msg, &msg);
                for (int i = 0; i < players.size(); i++)
                {
                    if (players[i].Exist())
                    {
                        Connection *conn_player = players[i].GetConnection();
                        // if (conn != conn_player)
                        // {
                        conn_player->GetOutbuffer() += msg;
                        // std::cout << "conn_player->GetOutbuffer() " << conn_player->GetOutbuffer() << std::endl;
                        conn_player->GetWriter()(conn_player);
                        // }
                    }
                }
            }
        }

        // 检测宝剑是否与玩家发生碰撞
        // {
        //     for (int i = 0; i < rooms[fd_to_room_number[conn->GetFd()]]->GetPlayersNumber().size(); i++)
        //     {
        //         int player_index = cur_member[i] - '0';
        //         if (req->_player_id != player_index)
        //         {
        //             if (CheckPlayerCollision(players[req->_player_id], players[player_index]))
        //             {

        //                 std::string msg;
        //                 Json::Value root;
        //                 root["server_type"] = PlayerCollision;
        //                 root["player_id"] = player_index;
        //                 root["color"] = players[req->_player_id]._color;

        //                 Json::FastWriter writer;
        //                 msg = writer.write(root);
        //                 // std::cout << "Player coor : " << players[req->_player_id]._x << " " << players[req->_player_id]._y << msg;
        //                 // std::cout << "PlayerCollision msg: " << msg;
        //                 Package(msg, &msg);
        //                 for (int i = 0; i < players.size(); i++)
        //                 {
        //                     if (players[i].Exist())
        //                     {
        //                         Connection *conn_player = players[i].GetConnection();
        //                         // if (conn != conn_player)
        //                         // {
        //                         conn_player->GetOutbuffer() += msg;
        //                         // std::cout << "conn_player->GetOutbuffer() " << conn_player->GetOutbuffer() << std::endl;
        //                         conn_player->GetWriter()(conn_player);
        //                         // }
        //                     }
        //                 }
        //             }
        //         }
        //     }
        // }

        // 检测宝剑是否与其他宝剑发生碰撞
        {
            for (int i = 0; i < rooms[fd_to_room_number[conn->GetFd()]]->GetPlayersNumber().size(); i++)
            {
                int player_index = cur_member[i] - '0';
                if (req->_player_id != cur_member[i] - '0')
                {
                    if (CheckSwordCollision(players[req->_player_id], players[player_index]))
                    {

                        std::string msg;
                        Json::Value root;
                        root["server_type"] = SwordCollision;
                        // root["player_id1"] = req->_player_id;
                        // root["radian1"] = players[req->_player_id]._sword._radian;
                        // root["rotation_direction1"] = players[req->_player_id]._sword.rotation_direction;

                        root["player_id"] = player_index;
                        // root["radian2"] = players[player_index]._sword._radian;
                        root["rotation_direction"] = players[player_index]._sword.rotation_direction;

                        Json::FastWriter writer;
                        msg = writer.write(root);
                        // std::cout << "Player coor : " << players[req->_player_id]._x << " " << players[req->_player_id]._y << msg;
                        // std::cout << "SwordCollision msg: " << msg;
                        Package(msg, &msg);
                        for (int i = 0; i < players.size(); i++)
                        {
                            if (players[i].Exist())
                            {
                                Connection *conn_player = players[i].GetConnection();
                                // if (conn != conn_player)
                                // {
                                conn_player->GetOutbuffer() += msg;
                                // std::cout << "conn_player->GetOutbuffer() " << conn_player->GetOutbuffer() << std::endl;
                                conn_player->GetWriter()(conn_player);
                                // }
                            }
                        }
                    }
                }
            }
        }

        // 检测宝剑是否超出边界
        {
            if (CheckEdgeCollision(players[req->_player_id]))
            {
                while (CheckEdgeCollision(players[req->_player_id]))
                {
                    players[req->_player_id]._sword._radian -= players[req->_player_id]._sword.rotation_direction * 0.01;
                }
                OppositeDirection(players[req->_player_id]._sword.rotation_direction);
            }
        }

        // 同步到本地的宝剑状态
        players[req->_player_id]._sword.Move();

        std::string msg;
        Json::Value root;
        root["server_type"] = SwordMove;
        root["player_id"] = req->_player_id;
        root["radian"] = players[req->_player_id]._sword._radian;
        root["rotation_direction"] = players[req->_player_id]._sword.rotation_direction;
        root["x"] = players[req->_player_id]._x;
        root["y"] = players[req->_player_id]._y;

        // 服务器统一倒计时
        auto delta_time = (Time::GetCurTimeStamp() - rooms[fd_to_room_number[conn->GetFd()]]->GetStartDownCount()) / 1000.0;
        std::cout << "delta_time: " << delta_time <<std::endl;
        g_countdown = g_countdown - delta_time;
        root["countdown"] = g_countdown;

        Json::FastWriter writer;
        msg = writer.write(root);
        // std::cout << "Player coor : " << players[req->_player_id]._x << " " << players[req->_player_id]._y << msg;
        std::cout << "SwordMove msg: " << msg;
        Package(msg, &msg);
        for (int i = 0; i < players.size(); i++)
        {
            if (players[i].Exist())
            {
                Connection *conn_player = players[i].GetConnection();
                // if (conn != conn_player)
                // {
                conn_player->GetOutbuffer() += msg;
                // std::cout << "conn_player->GetOutbuffer() " << conn_player->GetOutbuffer() << std::endl;
                conn_player->GetWriter()(conn_player);
                // }
            }
        }

        // std::string msg;
        // Json::Value root;
        // root["server_type"] = SwordMove;
        // for (int i = 0; i < players.size(); i++)
        // {
        //     if (players[i].Exist())
        //     {
        //         // std::cout << "i: " << i << std::endl;
        //         Connection *conn_player = players[i].GetConnection();
        //         if (conn == conn_player)
        //         {
        //             root["player_id"] = i;
        //             break;
        //         }
        //     }
        // }
        // root["radian"] = req->_radian;
        // root["rotation_direction"] = req->_rotation_direction;

        // Json::FastWriter writer;
        // msg = writer.write(root);
        // std::cout << "sword move msg: " << msg;
        // Package(msg, &msg);
        // for (int i = 0; i < players.size(); i++)
        // {
        //     if (players[i].Exist())
        //     {
        //         Connection *conn_player = players[i].GetConnection();
        //         // if (conn != conn_player)
        //         // {
        //         conn_player->GetOutbuffer() += msg;
        //         // std::cout << "conn_player->GetOutbuffer() " << conn_player->GetOutbuffer() << std::endl;
        //         conn_player->GetWriter()(conn_player);
        //         // }
        //     }
        // }

        return true;
    }

    virtual bool Deserialize(const std::string &result)
    {
        // Json::Value root;
        // Json::Reader reader;
        // reader.parse(result, root);

        // _player_id = root["player_id"].asInt();
        // _player_to_right = root["player_to_right"].asBool();
        // _player_to_left = root["player_to_left"].asBool();
        // _player_to_up = root["player_to_up"].asBool();
        // _player_to_down = root["player_to_down"].asBool();

        return true;
    }

    virtual ~ResponseSwordMove() {}

private:
    // int _player_id = -1;
};